#!/bin/bash
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

# Use a custom termcap for the Azure Linux installer in an ISO environment
# for a high contrast cursor. This is based on the "linux" termcap.
export TERMINFO=/usr/lib/mariner/terminfo
export TERM=mariner-installer

ISO_ROOT=/mnt/cdrom
CONFIG_ROOT=$ISO_ROOT/config
UNATTENDED_CONFIG_FILE=$CONFIG_ROOT/unattended_config.json
UNATTENDED_LOCK_FILE=/var/lock/unattended.lock

# PXE boot setup
CMDLINE=/proc/cmdline

# parse script parameters:
#
# -c -> config root folder (optional)
# -u -> unattended config file (optional)

while getopts ":c:u:" OPTIONS; do
  case "${OPTIONS}" in
    c ) CONFIG_ROOT=$OPTARG ;;
    u ) UNATTENDED_CONFIG_FILE=$OPTARG ;;

    \? )
        echo "Error - Invalid Option: -$OPTARG" 1>&2
        exit 1
        ;;
    : )
        echo "Error - Invalid Option: -$OPTARG requires an argument" 1>&2
        exit 1
        ;;
  esac
done

# Mounting the ISO root for the installer.
mkdir -p $ISO_ROOT
LABEL=CDROM

function retry {
    local retry=0
    local limit=10
    local sleep_seconds=15
    while [ $retry -lt $limit ]
    do
        eval "$@" && break
        echo "$@" failed. Retrying...
        ((retry++))
        sleep $sleep_seconds
    done
}

if grep -qs $ISO_ROOT /proc/mounts; then
    echo ISO root already mounted
# Read from /proc/cmdline to get image configs from PXE server
elif grep -q "image-config" $CMDLINE; then
    IMAGE_CONFIG_VALUE=$(grep -oP "(?<=--image-config=)\S+" "$CMDLINE")
    # $IMAGE_CONFIG_VALUE will be in this fixed format: http://PXE_SERVER_IP/RANDOM_PATH
    # CUT_DIRS will be an array of strings separated by '/'
    IFS='/' read -ra CUT_DIRS <<< $IMAGE_CONFIG_VALUE
    
    # It is possible that the installation environment does not have network access yet when
    # this script is first run. So use a retry loop 
    PXE_SERVER_IP=$(echo "$IMAGE_CONFIG_VALUE" | sed -e 's|^[^/]*//||' -e 's|/.*$||')
    retry ping -c 1 $PXE_SERVER_IP

    # To disable generation of any extra directories and just download the contents within the directory, 
    # use -nH to disable genration of host-prefix, "PXE_SERVER_IP". 
    # To disable generation of "RANDOM_PATH", set --cut-dirs to the number of strings separated by '/'. 
    # Please note that http://PXE_SERVER_IP will generate 3 strings separated by '/': "http:", "" and "PXE_SERVER_IP", 
    # and thus the number of strings separated by '/' within "RANDOM_PATH" will be the length of $CUT_DIRS minus 3
    wget -r --no-parent -nH --cut-dirs=$((${#CUT_DIRS[@]}-3)) --directory-prefix="$CONFIG_ROOT" --reject="index.html*" "$IMAGE_CONFIG_VALUE"/
    # Enable all scripts under config directory to be executable
    find "$CONFIG_ROOT"/ -type f -iname "*.sh" -exec chmod a+x {} \;
else
    echo Attempt to mount the ISO root
    # It is possible that the partition isn't ready to be mounted when this script
    # is first run. So use a retry loop. There is a race condition here where the
    # partition could be mounted between the first grep and the mount. If this happens
    # the mount will fail and the retry loop would retry the mount repeatedly. This
    # is handled by the 'or' in the retry loop which will grep for the mount point and
    # break out of the loop if it is found.
    retry "{ mount -L $LABEL -o ro $ISO_ROOT || grep -qs $ISO_ROOT /proc/mounts ; }"
fi

# If we are running unattended (i.e., have $UNATTENDED_CONFIG_FILE), we need to make sure that we only run once.
# We can use flock to synchronize the unattended install flows.
if [[ -f "$UNATTENDED_CONFIG_FILE" ]]; then
    echo "Synchronizing unattended install flows... current sessions are:"
    who
    thisTerminal=$(who -m | xargs | cut -d' ' -f2)
    echo "This instance is on '$thisTerminal'"

    # Generally we want to prioritize ttyS0 since that will be used for debugging. The output from the log file will
    # contain the timestamp and color codes so it is still useful for debugging and showing liveness but it will look
    # messy.
    if [[ "$thisTerminal" != "ttyS0" ]]; then
        echo "Pausing for 2 seconds to allow other session to take priority"
        sleep 2
    fi

    # Create a lock file and open file descriptor 200 to it (200 is chosen arbitrarily)
    # The exec will hold the file descriptor open for the duration of the script since the flock will only
    # work on file descriptors that are open.
    touch "$UNATTENDED_LOCK_FILE"
    exec 200>> "$UNATTENDED_LOCK_FILE"

    # If the file descriptor is already locked bail out immediately and just follow the other installer's log. The tail
    # command will follow the log file and should never exit. We must ensure that this instance of the installer does
    # not run any further so we always exit 0 just in case.
    if ! flock -x -n 200; then
        echo "Unattended install already running, following other installer's log instead" 
        sleep 5
        tail -f -n 10000 /installer/log.txt 
        exit 0
    fi
fi

if [[ ! -f "$UNATTENDED_CONFIG_FILE" ]]; then
    # Restrict speakup use to attended installs
    # FIXME(thcrain-msft)
    # This is a loop of silence to keep the default audio device alive
    # This is a temporary workaround that is needed for VirtualBox,
    # which is currently the most convenient platform to test on which
    # has sound driver support. It creates a bit of hiss.
    speaker-test -l0 -t wav -w ../../../../root/silence.wav -r 22050 >/dev/null 2>&1 &

    # Set better defaults for speakup punctuation level/speed
    echo 2 > /sys/accessibility/speakup/punc_level
    echo 2 > /sys/accessibility/speakup/reading_punc
    echo 2 > /sys/accessibility/speakup/soft/rate

    # Ensure the userspace speakup connector is up
    systemctl enable espeakup
    systemctl start espeakup
fi

cd /installer

# Turn off echoing while the installer runs to stop sensitive data from rendering in the TTY session.
stty -echo

# add call to static time file to populate liveinstaller option here
if [[ -f "$CONFIG_ROOT/repo-snapshot-time.txt" ]]; then
REPO_TIME=$(cat /"$CONFIG_ROOT/repo-snapshot-time.txt")
fi

./liveinstaller --base-dir $CONFIG_ROOT --imager /installer/imager --input $UNATTENDED_CONFIG_FILE --template-config $CONFIG_ROOT/attended_config.json \
                --build-dir $PWD --log-file=/installer/log.txt --repo-snapshot-time="$REPO_TIME"
installerExitCode=$?

# Consume any buffered stdin to prevent it from being passed to any future programs,
# as it may contain sensitive data
while read -t 1 -n 10000
do
    echo ""
done

# Turn back on echoing input so the TTY session is usable for the user.
stty echo

if [ $installerExitCode -eq 0 ]; then
    reboot
else
    /bin/bash
fi
